package com.example.user.coolrun.runnershign;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;

import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

//使用Block生成地面和随机障碍，同时设置移动的速度
public class Level {
	private int width;
	private int height;
	private float levelPosition;
	private float deltaLevelPosition;

	public float baseSpeed;
	public float baseSpeedStart;
	public float baseSpeedMax;
	public float baseSpeedMaxStart;
	public float baseSpeedAcceleration;

	public float extraSpeed;
	public float extraSpeedStart;
	public float extraSpeedMax;
	public float extraSpeedMaxStart;
	public float extraSpeedAcceleration;

	public int timeUntilNextSpeedIncreaseMillis;

	public static Block[] blockData;
	public static final int maxBlocks = 5;
	private int leftBlockIndex;
	private int rightBlockIndex;

	public static Obstacle[] obstacleDataSlower;
	public static final int maxObstaclesSlower = maxBlocks;
	private int leftSlowerIndex;
	private int rightSlowerIndex;

	private float obstacleSlowerWidth;
	private float obstacleSlowerHeight;


	private final int OBSTACLEMASK_0_NO_OBSTACLE = 80;
	private final int OBSTACLEMASK_1_JUMP = 30;
	private final int OBSTACLEMASK_2_SLOW = 30;
	private final int OBSTACLEMASK_3_JUMP_SLOW = 20;
	private final int OBSTACLEMASK_4_BONUS = 40;
	private final int OBSTACLEMASK_5_JUMP_BONUS = 20;
	private final int OBSTACLEMASK_6_SLOW_BONUS = 20;
	private final int OBSTACLEMASK_7_JUMP_SLOW_BONUS = 10;

	private final int OBSTACLEMASK_MAX =250;

	private Bitmap obstacleSlowImg = null;

	private boolean slowDown;
	private int BlockCounter;
	private OpenGLRenderer renderer;

	private Random randomGenerator;
	private boolean lastBlockWasSmall = false;
	private int minBlockWidth = 0;


	private RHDrawable mWaves = null;

	public Level(Context context, OpenGLRenderer glrenderer, int _width, int _heigth) {
		if(Settings.RHDEBUG)
			Log.d("debug", "in Level constructor");

		width = _width;
		height = _heigth;
		levelPosition = 0;
		;
		deltaLevelPosition = 0;

		baseSpeedStart = Util.getPercentOfScreenWidth(0.095f);
		baseSpeed = baseSpeedStart;
		baseSpeedMaxStart = Util.getPercentOfScreenWidth(0.18f);
		baseSpeedMax = baseSpeedMaxStart;
		baseSpeedAcceleration = baseSpeed*0.02f;

		extraSpeedStart = Util.getPercentOfScreenWidth(0.015f);
		extraSpeed = extraSpeedStart;
		extraSpeedMaxStart = Util.getPercentOfScreenWidth(0.3f);
		extraSpeedMax = extraSpeedMaxStart;
		extraSpeedAcceleration = extraSpeed * 0.004f;

		timeUntilNextSpeedIncreaseMillis = Settings.TimeOfFirstSpeedIncrease;

		obstacleSlowerWidth = Util.getPercentOfScreenWidth(3);
		obstacleSlowerHeight= Util.getPercentOfScreenHeight(10);


		if(Settings.RHDEBUG){
			Log.d("debug", "obstacleSlowerWidth" + obstacleSlowerWidth);
			Log.d("debug", "obstacleSlowerHeight" + obstacleSlowerHeight);

		}
		renderer = glrenderer;


		randomGenerator = new Random();

		blockData = new Block[maxBlocks];
		leftBlockIndex = 0;
		rightBlockIndex = maxBlocks;

		obstacleDataSlower = new Obstacle[maxObstaclesSlower];
		leftSlowerIndex = 0;
		rightSlowerIndex = maxObstaclesSlower;
		obstacleSlowImg = Util.loadBitmapFromAssets("game_obstacle_slow.png");
		Block.setTextureLeft(Util.loadBitmapFromAssets("game_block_left.png"));
		Block.setTextureMiddle(Util.loadBitmapFromAssets("game_block_middle.png"));
		Block.setTextureRight(Util.loadBitmapFromAssets("game_block_right.png"));

		slowDown = false;

		initializeBlocks(true);
		initializeObstacles(true);

		mWaves = new RHDrawable(0, 0, 0.7f, width*4, height);
		mWaves.loadBitmap(Util.loadBitmapFromAssets("game_waves.png")
				, GL10.GL_REPEAT, GL10.GL_CLAMP_TO_EDGE);
		renderer.addMesh(mWaves);
	}

	public void cleanup() {
		if (obstacleSlowImg != null) obstacleSlowImg.recycle();
		Block.cleanup();
	}

	public void update() {
		synchronized (blockData) {

			if (0 > blockData[leftBlockIndex].BlockRect.right) {
				appendBlockToEnd(-1);

				if(BlockCounter == 5)
					appendObstaclesToEnd(false);
				if(BlockCounter == 7)
					appendObstaclesToEnd( false);
				if(BlockCounter == 9)
					appendObstaclesToEnd(true);
				if (BlockCounter > 15)
					decideIfAndWhatObstaclesSpawn();
			}

			baseSpeedAcceleration = baseSpeed * 0.005f;
			extraSpeedAcceleration = extraSpeed * 0.002f;

			if(Util.getTimeSinceRoundStartMillis() > timeUntilNextSpeedIncreaseMillis){
				timeUntilNextSpeedIncreaseMillis += Settings.timeToFurtherSpeedIncreaseMillis;
				baseSpeedMax += Util.getPercentOfScreenWidth(0.075f);
			}

			if(baseSpeed < baseSpeedMax)
				baseSpeed+=baseSpeedAcceleration;

			if(extraSpeed < extraSpeedMax)
				extraSpeed+=extraSpeedAcceleration;

			if(slowDown){
				baseSpeed=baseSpeedStart;
				extraSpeed /= 2;
				slowDown=false;
			}
			deltaLevelPosition = baseSpeed + extraSpeed;
			levelPosition += deltaLevelPosition;

			mWaves.x -= deltaLevelPosition+2;
			if (mWaves.x < -mWaves.width/2)
				mWaves.x = 0;


			for (int i = 0; i < maxBlocks; i++)
			{
				blockData[i].x -= deltaLevelPosition;
				blockData[i].updateRect();
			}

			for (int i = 0; i < maxObstaclesSlower; i++)
			{
				obstacleDataSlower[i].x -= deltaLevelPosition;
			}
		}
	}

	private void initializeBlocks(Boolean firstTime) {
		if(Settings.RHDEBUG)
			Log.d("debug", "in initializeBlocks");
		if (firstTime)
			blockData[0]=new Block();
		blockData[0].x = 0;
		blockData[0].setWidth(width);
		blockData[0].setHeight(Settings.FirstBlockHeight);
		blockData[0].updateRect();

		if(Settings.RHDEBUG)
			Log.d("debug", "after blockdata 0");

		if(firstTime)
			renderer.addMesh(blockData[0]);

		leftBlockIndex = 1;
		rightBlockIndex = 0;

		if(Settings.RHDEBUG)
			Log.d("debug", "before for");

		for(int i = 1; i < maxBlocks; i++)
		{
			if (firstTime){
				blockData[i] = new Block();
				renderer.addMesh(blockData[i]);
			}
			appendBlockToEnd(i);
			blockData[i].updateRect();
		}
		if(Settings.RHDEBUG)
			Log.d("debug", "left initializeBlocks");
	}

	private void appendBlockToEnd(int BlockNumber)
	{
		if (minBlockWidth == 0) {
			minBlockWidth =
					Block.getTextureLeftWidth() +
							Block.getTextureRightWidth() +
							Block.getTextureMiddleWidth() * 2;
		}
		float newHeight=0;
		float oldHeight;
		float newWidth=0;
		float distance;
		float newLeft;
		boolean thisBlockIsSmall = false;

		oldHeight = blockData[rightBlockIndex].BlockRect.top;

		if(BlockNumber==-1){
			if (oldHeight > height/2)
				newHeight = (int)(Math.random()*height/3*2 + height/8);
			else
				newHeight = (int)(Math.random()*height/4 + height/8);

			if(Util.getTimeSinceRoundStartMillis() > Settings.timeUntilLongBlocksStopMillis){
				if (lastBlockWasSmall) lastBlockWasSmall = false;
				else if (50 - BlockCounter <= 0) thisBlockIsSmall = true;
				else thisBlockIsSmall = (randomGenerator.nextInt(50 - BlockCounter) <= 5);

				if (thisBlockIsSmall) {
					newWidth = minBlockWidth;
					lastBlockWasSmall = true;
				}
				else {
					newWidth = (int)(Math.random()*width/3+width/3);
				}
			}else{
				newWidth = (int)(Math.random()*width/3+width*0.70f);
			}

			newWidth -= (newWidth - Block.getTextureLeftWidth() - Block.getTextureRightWidth()) % (Block.getTextureMiddleWidth());

			distance = (int)(Math.random()*width/16+width/12);

			if(distance <= Player.width)
				distance = Player.width+10;
		}else{
			distance = Player.width+5;
			switch (BlockNumber){
				case 1:
					newHeight=oldHeight;
					newWidth=Util.getPercentOfScreenWidth(80);
					break;
				case 2:
					newHeight=oldHeight+Util.getPercentOfScreenHeight(8);
					newWidth=Util.getPercentOfScreenWidth(80);
					break;
				case 3:
					newHeight=oldHeight;
					newWidth=Util.getPercentOfScreenWidth(80);
					break;
				case 4:
					newHeight=oldHeight+Util.getPercentOfScreenHeight(9);
					newWidth=Util.getPercentOfScreenWidth(80);
					break;
			}
		}

		newLeft = blockData[rightBlockIndex].BlockRect.right + distance;

		blockData[leftBlockIndex].setHeight(newHeight);
		blockData[leftBlockIndex].setWidth(newWidth);
		blockData[leftBlockIndex].x = newLeft;

		leftBlockIndex++;
		if (leftBlockIndex == maxBlocks)
			leftBlockIndex = 0;

		rightBlockIndex++;
		if (rightBlockIndex== maxBlocks)
			rightBlockIndex = 0;

		BlockCounter++;

	}

	private void initializeObstacles(Boolean firstTime)
	{

		for(int i = 0; i < maxObstaclesSlower; i++)
		{
			if (firstTime)
			{
				obstacleDataSlower[i] = new Obstacle(-1000, 0, 0.9f, obstacleSlowerWidth, obstacleSlowerHeight, 's');
				renderer.addMesh(obstacleDataSlower[i]);
				obstacleDataSlower[i].loadBitmap(obstacleSlowImg);
			}

			obstacleDataSlower[i].x = -1000;
			obstacleDataSlower[i].didTrigger = false;
		}

	}

	private void decideIfAndWhatObstaclesSpawn()
	{
		int obstacleValue =randomGenerator.nextInt(OBSTACLEMASK_MAX);

		if (obstacleValue < OBSTACLEMASK_0_NO_OBSTACLE)
		{
			return;
		}
		obstacleValue -= OBSTACLEMASK_0_NO_OBSTACLE;

		if (obstacleValue < OBSTACLEMASK_1_JUMP)
		{
			appendObstaclesToEnd(false);
			return;
		}
		obstacleValue -= OBSTACLEMASK_1_JUMP;

		if (obstacleValue < OBSTACLEMASK_2_SLOW)
		{
			appendObstaclesToEnd( true);
			return;
		}
		obstacleValue -= OBSTACLEMASK_2_SLOW;

		if (obstacleValue < OBSTACLEMASK_3_JUMP_SLOW)
		{
			appendObstaclesToEnd(false);
			return;
		}
		obstacleValue -= OBSTACLEMASK_3_JUMP_SLOW;

		if (obstacleValue < OBSTACLEMASK_4_BONUS)
		{
			appendObstaclesToEnd( false);
			return;
		}
		obstacleValue -= OBSTACLEMASK_4_BONUS;

		if (obstacleValue < OBSTACLEMASK_5_JUMP_BONUS)
		{
			appendObstaclesToEnd(false);
			return;
		}
		obstacleValue -= OBSTACLEMASK_5_JUMP_BONUS;

		if (obstacleValue < OBSTACLEMASK_6_SLOW_BONUS)
		{
			appendObstaclesToEnd( true);
			return;
		}
		obstacleValue -= OBSTACLEMASK_6_SLOW_BONUS;

		if (obstacleValue < OBSTACLEMASK_7_JUMP_SLOW_BONUS)
		{
			appendObstaclesToEnd(false);
			return;
		}

	}

	private void appendObstaclesToEnd (Boolean spawnSlower)
	{
		if (spawnSlower)
		{
			float obstacleLeft;

			// compute a fraction of the range, 0 <= frac < range
			long fraction = (long)(blockData[rightBlockIndex].mWidth * 0.33 * randomGenerator.nextDouble());

			Obstacle newSlowObstacle = obstacleDataSlower[leftSlowerIndex];
			newSlowObstacle.didTrigger = false;

			obstacleLeft =
					blockData[rightBlockIndex].x + blockData[rightBlockIndex].mWidth
							- newSlowObstacle.width - fraction;

			newSlowObstacle.x = obstacleLeft;
			newSlowObstacle.y = blockData[rightBlockIndex].mHeight;
			newSlowObstacle.setObstacleRect(
					obstacleLeft,
					obstacleLeft+newSlowObstacle.width,
					blockData[rightBlockIndex].mHeight,
					blockData[rightBlockIndex].mHeight-newSlowObstacle.height);

			leftSlowerIndex++;
			if (leftSlowerIndex == maxObstaclesSlower)
				leftSlowerIndex = 0;

			rightSlowerIndex++;
			if (rightSlowerIndex == maxObstaclesSlower)
				rightSlowerIndex = 0;

		}
	}

	//得到距离分数
	public int getDistanceScore()
	{
		return (int)(levelPosition * 800 / width / 10);
	}

	//返回水平坐标（相对高度，用于判断是否死亡）
	public float getLevelPosition(){
		return levelPosition;
	}

	//初始化
	public void reset() {
		synchronized (blockData) {
			levelPosition = 0;

			initializeBlocks(false);
			initializeObstacles(false);

			timeUntilNextSpeedIncreaseMillis = Settings.TimeOfFirstSpeedIncrease;

			baseSpeed = baseSpeedStart;
			extraSpeed = extraSpeedStart;
			baseSpeedMax = baseSpeedMaxStart;
			extraSpeedMax = extraSpeedMaxStart;
			BlockCounter=0;
		}
	}
}



